package com.zy.stock.quartz;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.zy.stock.domain.Stock;
import com.zy.stock.domain.StockCrawlRecord;
import com.zy.stock.domain.StockTranscation;
import com.zy.stock.domain.User;
import com.zy.stock.domain.UserStockRl;
import com.zy.stock.dto.UserStockRlDto;
import com.zy.stock.mapper.StockCrawlRecordMapper;
import com.zy.stock.mapper.StockTranscationMapper;
import com.zy.stock.mapper.UserStockRlMapper;
import com.zy.stock.service.StockService;
import com.zy.stock.service.StockTranscationService;
import com.zy.stock.service.UserService;
import com.zy.stock.service.UserStockRlService;

/**
 * 分析股票形式 定时作业
 * @author zhangyi
 *
 */
@Component
public class AnalyzeJob {
	
	private Logger logger = LoggerFactory.getLogger(AnalyzeJob.class);
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private StockTranscationService stockTranscationService;
	
	@Autowired
	private StockTranscationMapper stockTranscationMapper;
	
	@Autowired
	private UserStockRlService userStockRlService;
	
	@Autowired
	private StockService stockService;
	
	@Autowired
	private UserStockRlMapper userStockRlMapper;
	
	@Autowired
	private StockCrawlRecordMapper stockCrawlRecordMapper;
	
	/**
	 * @throws Exception
	 */
	public void analyze()throws Exception{
		//遍历账户
		List<User> users = userService.findAll();
		for(User user:users){
			//收集建仓提醒
			analyzeBuildAlert(user);
			//遍历每只持有的股票 分析首次补仓提醒
			analyzeFirstAdd(user);
			//二次补仓提醒
			analyzeSecondAdd(user);
		}		
	}
	
	
	
	/**
	 * 二次补仓提醒
	 * @param user
	 * @throws Exception 
	 */
	private void analyzeSecondAdd(User user) throws Exception {
		// TODO Auto-generated method stub
		List<Stock> stocks = stockService.findAll();
		for(Stock stock:stocks){
			String status = stock.getStatus();
			if(status.equals("待观察")){
				continue;//待观察的股票不考虑提醒
			}
			//已经首次补仓的情况下 考虑二次补仓
			if(isCanSecondAdd(user, stock)){
				Double addCost = stock.getAppraisement()/(1.3*1.002);//二次补仓成本
				//计算补仓数量
				Double totalCost = new Double(0);//首次补仓总投入
				if(user.getType()==1){
					totalCost = user.getPrincipal()/10;
					Integer num = getFirstAddNumAfterBuild(addCost, stock, user,totalCost);
					//计算补仓价格
					Double firstAddValue = getFirstAddValueAfterBuild(addCost, stock, user, num);
					//判断价格区间是否满足
					Double value = stock.getValue();
					//判断是否达到补仓价格区间
					if(firstAddValue!=null&&value!=null){
						if(value*0.9<=firstAddValue&&firstAddValue<=value*1.1){
							createSecondAddAlert(firstAddValue,num,user,stock);
						}else{
							logger.info(stock.getName()+"二次补仓预警价为 "+firstAddValue+" 收盘价为 "+value+" 无法补仓");
						}
					}else{
						logger.error(stock.getName()+"没有设置估值或者收盘价为空");
					}	
				}else{
					logger.info("小投入账户 不进行二次补仓");
					return;
				} 
			}
		}
	}

	/**
	 * 处理首页补仓提醒
	 * @param user
	 * @throws Exception 
	 */
	private void analyzeFirstAdd(User user) throws Exception {
		// TODO Auto-generated method stub
		List<Stock> stocks = stockService.findAll();
		for(Stock stock:stocks){
			String status = stock.getStatus();
			if(status.equals("待观察")){
				continue;//待观察的股票不考虑提醒
			}
			
			//已经建仓的情况下 判断首补
			if(isCanAdd(user, stock)){
				Double addCost = 1.1*stock.getAppraisement()/(1.3*1.002);//首次补仓成本
				//计算补仓数量
				Double totalCost = new Double(0);//首次补仓总投入
				if(user.getType()==1){
					totalCost = user.getPrincipal()/10*0.6;
				}else{
					totalCost = user.getPrincipal()/5;
				} 
				Integer num = getFirstAddNumAfterBuild(addCost, stock, user,totalCost);
				//计算补仓价格
				Double firstAddValue = getFirstAddValueAfterBuild(addCost, stock, user, num);
				//判断价格区间是否满足
				Double value = stock.getValue();
				//判断是否达到补仓价格区间
				if(firstAddValue!=null&&value!=null){
					if(value*0.9<=firstAddValue&&firstAddValue<=value*1.1){
						createFirstAddAlert(firstAddValue,num,user,stock);
					}else{
						logger.info(stock.getName()+"首次补仓预警价为 "+firstAddValue+" 收盘价为 "+value+" 无法补仓");
					}
				}else{
					logger.error(stock.getName()+"没有设置估值或者收盘价为空");
				}	
			}
		}
	}

	/**
	 * 处理建仓提醒的判断
	 * @param user
	 * @throws Exception 
	 */
	private void analyzeBuildAlert(User user) throws Exception{
		List<Stock> stocks = stockService.findAll();
		for(Stock stock:stocks){
			String status = stock.getStatus();
			String crawlStatus = stock.getCrawlStatus();
			if(status.equals("待观察")||crawlStatus.indexOf("停牌")!=-1){
			  logger.info(stock.getName()+"停牌或者是待观察的");
			    continue;//待观察的股票 和停牌的股票不考虑提醒
			}
			//判断是否符合预警价格
			Double appraisement = stock.getAppraisement();
			Double value = stock.getValue();
			Double alertValue = 1.15*appraisement/1.3/1.002;
			Double alertValueGe = value*0.9;
		    Double alertValueLe = value*1.1;
			logger.info(stock.getName()+"的预警价是"+alertValue+" 收盘价是 "+value);
			if(appraisement!=null&&value!=null){
				if(alertValueGe<=alertValue){
					//只有符合基本条件 就是未持有股票 或者股票状态匹配 才进行预警价格判断
					if(isCanBuild(user, stock)){
						logger.info("stock is "+JSONObject.toJSONString(stock));
						if(stock.getId()==16){
							logger.info("firstAddValue is null");
						}
						StockTranscation add_stockTranscation = createBuildAlert(user, stock);
						//这里要判断是否同时可以创建首补提醒
						//计算首次补仓数量
						Integer num = 0;//首次补仓数量
						Double addCost = 1.1*stock.getAppraisement()/(1.3*1.002);//首次补仓成本
						Double totalCost = new Double(0);//首次补仓总投入
						if(user.getType()==1){
							totalCost = user.getPrincipal()/10*0.6;
						}else{
							totalCost = user.getPrincipal()/5;
						} 
						
						BigDecimal num_DoubleValue = new BigDecimal((totalCost-(add_stockTranscation.getOperateNum()*addCost))/(addCost));
						logger.info(num_DoubleValue.toString());
						num_DoubleValue = num_DoubleValue.setScale(-2, BigDecimal.ROUND_HALF_UP);
						if(num_DoubleValue.doubleValue()<=100){
							num = 100;
						}else{
							num = num_DoubleValue.intValue();
						}
						logger.info(stock.getName()+"补仓数量为 "+num);
						//计算首次补仓价格
						Double firstAddValue = new Double(0);
						//按照建仓推荐价格和数量计算 当前成本
						Double currentCost = userStockRlService.getCost(add_stockTranscation.getOperateNum(),add_stockTranscation.getSuggestValue(),add_stockTranscation.getStockCode());
						firstAddValue = (addCost*(add_stockTranscation.getOperateNum()+num)-add_stockTranscation.getOperateNum()*currentCost)/num;
						//保留小数点后两位
						if(firstAddValue==null){
							logger.info("firstAddValue is null");
						}else{
							logger.info("firstAddValue is "+firstAddValue);						
							BigDecimal b = new BigDecimal(firstAddValue); 
							firstAddValue = b.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();   
						}
						logger.info(stock.getName()+"补仓价格为 "+firstAddValue);
						//判断是否收盘价达到首次补仓价格区间
						if(firstAddValue!=null&&value!=null){
							if(value*0.9<=firstAddValue&&firstAddValue<=value*1.1){
								createFirstAddAlert(firstAddValue,num,user,stock);
							}else{
								logger.info(stock.getName()+"首次补仓预警价为 "+firstAddValue+" 收盘价为 "+value+" 无法补仓");
							}
						}else{
							logger.error(stock.getName()+"没有设置估值或者收盘价为空");
						}	
					}
				}else{
					//判断是否出现股价变动异常
					
				}
			}else{
				logger.error(stock.getName()+"没有设置估值或者收盘价为空");
			}		
		}
	}
	
	/** 对某个账户的某个股票验证建仓提醒 主要用户测试找问题
	 * 
	 * @param user
	 * @param stock
	 * @throws Exception
	 */
	public void analyzeBuildAlert(User user,Stock stock) throws Exception{
	  String status = stock.getStatus();
      if(status.equals("待观察")){
          logger.info(stock.getName()+" 待观察的股票不考虑提醒");//
      }
    //判断是否符合预警价格
      Double appraisement = stock.getAppraisement();
      Double value = stock.getValue();
      Double alertValue = 1.15*appraisement/1.3/1.002;
      Double alertValueGe = value*0.9;
      Double alertValueLe = value*1.1;
      
      if(appraisement!=null&&value!=null){
          if(alertValueGe<=alertValue&&alertValue<=alertValueLe){
              //只有符合基本条件 就是未持有股票 或者股票状态匹配 才进行预警价格判断
              if(isCanBuild(user, stock)){
                  logger.info("stock is "+JSONObject.toJSONString(stock));
                  if(stock.getId()==16){
                      logger.info("firstAddValue is null");
                  }
                  StockTranscation add_stockTranscation = createBuildAlert(user, stock);
                  //这里要判断是否同时可以创建首补提醒
                  //计算首次补仓数量
                  Integer num = 0;//首次补仓数量
                  Double addCost = 1.1*stock.getAppraisement()/(1.3*1.002);//首次补仓成本
                  Double totalCost = new Double(0);//首次补仓总投入
                  if(user.getType()==1){
                      totalCost = user.getPrincipal()/10*0.6;
                  }else{
                      totalCost = user.getPrincipal()/5;
                  } 
                  
                  BigDecimal num_DoubleValue = new BigDecimal((totalCost-(add_stockTranscation.getOperateNum()*addCost))/(addCost));
                  logger.info(num_DoubleValue.toString());
                  num_DoubleValue = num_DoubleValue.setScale(-2, BigDecimal.ROUND_HALF_UP);
                  if(num_DoubleValue.doubleValue()<=100){
                      num = 100;
                  }else{
                      num = num_DoubleValue.intValue();
                  }
                  logger.info(stock.getName()+"补仓数量为 "+num);
                  //计算首次补仓价格
                  Double firstAddValue = new Double(0);
                  //按照建仓推荐价格和数量计算 当前成本
                  Double currentCost = userStockRlService.getCost(add_stockTranscation.getOperateNum(),add_stockTranscation.getSuggestValue(),add_stockTranscation.getStockCode());
                  firstAddValue = (addCost*(add_stockTranscation.getOperateNum()+num)-add_stockTranscation.getOperateNum()*currentCost)/num;
                  //保留小数点后两位
                  if(firstAddValue==null){
                      logger.info("firstAddValue is null");
                  }else{
                      logger.info("firstAddValue is "+firstAddValue);                     
                      BigDecimal b = new BigDecimal(firstAddValue); 
                      firstAddValue = b.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();   
                  }
                  logger.info(stock.getName()+"补仓价格为 "+firstAddValue);
                  //判断是否收盘价达到首次补仓价格区间
                  if(firstAddValue!=null&&value!=null){
                      if(value*0.9<=firstAddValue&&firstAddValue<=value*1.1){
                          createFirstAddAlert(firstAddValue,num,user,stock);
                      }else{
                          logger.info(stock.getName()+"首次补仓预警价为 "+firstAddValue+" 收盘价为 "+value+" 无法补仓");
                      }
                  }else{
                      logger.error(stock.getName()+"没有设置估值或者收盘价为空");
                  }   
              }
          }else{
              //判断是否出现股价变动异常
              
          }
      }else{
          logger.error(stock.getName()+"没有设置估值或者收盘价为空");
      }       
	}
	
	/**
	 * 首次补仓操作
	 * @param user
	 * @param stock
	 * @throws Exception 
	 */
	private StockTranscation createBuildAlert(User user, Stock stock) throws Exception {
		// TODO Auto-generated method stub
		//计算建仓价格 1.15*估值/1.3/1.002
		Double totalCost = new Double(0);
		Double buildPrice = stock.getAppraisement()*1.15/1.3/1.002;
		BigDecimal b = new BigDecimal(buildPrice); 
		buildPrice = b.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();   
		Double doubleNum = 0d;
		Integer num = 0;
		if(user.getType()!=null){
			if(user.getType()==1){
				totalCost = user.getPrincipal()/10*0.2;
			}else{
				totalCost = user.getPrincipal()/5*0.6;
			} 
			//计算建仓数量
			doubleNum = (totalCost/(buildPrice));
			b = new BigDecimal(doubleNum); 
			if(b.doubleValue()<=100){
				num = 100;
			}else{
				doubleNum = b.setScale(-2,BigDecimal.ROUND_HALF_UP).doubleValue();  
				num = doubleNum.intValue();
			}
			logger.info(stock.getName()+" 建仓数量为 "+num);
			logger.info(stock.getName()+" 建仓价格为 "+buildPrice);
			
			//构造提醒
			StockTranscation obj = new StockTranscation();
			obj.setUserId(user.getId());
			obj.setUserName(user.getName());
			obj.setCreateTime(new Date());
			obj.setOperateNum(num);
			obj.setOperation("建仓");
			obj.setStockId(stock.getId());
			obj.setStockCode(stock.getCode());
			obj.setStockName(stock.getName());
			obj.setStatus("未完成");
			obj.setSuggestValue(buildPrice);
			obj.setYears("2017");
			stockTranscationMapper.save(obj);
			return obj;
		}else{
			logger.error(user.getName()+"没有账户类型");
			return null;
		}	
	}
	
	/**
	 * 创建首次补仓提醒
	 * @param firstAddValue
	 * @param num
	 * @param user
	 * @param stock
	 * @throws Exception 
	 */
	private void createFirstAddAlert(Double firstAddValue, Integer num,User user, Stock stock) throws Exception {
		// TODO Auto-generated method stub
		//构造提醒
		StockTranscation obj = new StockTranscation();
		obj.setUserId(user.getId());
		obj.setUserName(user.getName());
		obj.setCreateTime(new Date());
		obj.setOperateNum(num);
		obj.setOperation("首次补仓");
		obj.setStockId(stock.getId());
		obj.setStockCode(stock.getCode());
		obj.setStockName(stock.getName());
		obj.setStatus("未完成");
		obj.setSuggestValue(firstAddValue);
		obj.setYears("2016");
		stockTranscationMapper.save(obj);
	}
	
	
	/**
	 * 创建二次补仓提醒
	 * @param firstAddValue
	 * @param num
	 * @param user
	 * @param stock
	 */
	private void createSecondAddAlert(Double firstAddValue,Integer num,User user,Stock stock)throws Exception {
		// TODO Auto-generated method stub
		StockTranscation obj = new StockTranscation();
		obj.setUserId(user.getId());
		obj.setUserName(user.getName());
		obj.setCreateTime(new Date());
		obj.setOperateNum(num);
		obj.setOperation("二次补仓");
		obj.setStockId(stock.getId());
		obj.setStockCode(stock.getCode());
		obj.setStockName(stock.getName());
		obj.setStatus("未完成");
		obj.setSuggestValue(firstAddValue);
		obj.setYears("2016");
		stockTranscationMapper.save(obj);
	}

	/**
	 * 判断是否可以建仓
	 * @param user
	 * @param stock
	 * @return
	 */
	private boolean isCanBuild(User user,Stock stock){
		boolean isCanBuild = true;
		UserStockRlDto obj = new UserStockRlDto();
		obj.setStockCode(stock.getCode());
		obj.setYears("2016");
		obj.setUserName(user.getName());
		
		List<UserStockRl> userStockRls = userStockRlMapper.findByCase(obj);
		if(userStockRls!=null&&userStockRls.size()>0){
			for(UserStockRl rl:userStockRls){
				if(rl.getStatus().equals("建仓")||rl.getStatus().equals("首补")||rl.getStatus().equals("二次补仓")){
					isCanBuild = false;
					break;
				}
			}
		}
		logger.info(stock.getName()+" can build");
		return isCanBuild;	
	}
	
	/**
	 * 判断是否可以首补
	 * @param user
	 * @param stock
	 * @return
	 */
	private boolean isCanAdd(User user,Stock stock){
		boolean isCanBuild = false;
		UserStockRlDto obj = new UserStockRlDto();
		obj.setStockCode(stock.getCode());
		obj.setYears("2016");
		obj.setUserName(user.getName());
		obj.setStatus("建仓");
		
		List<UserStockRl> userStockRls = userStockRlMapper.findByCase(obj);
		if(userStockRls!=null&&userStockRls.size()>0){		
			isCanBuild = true;		
		}
		return isCanBuild;	
	}
	
	/**
	 * 判断是否可以二次补仓
	 * @param user
	 * @param stock
	 * @return
	 */
	private boolean isCanSecondAdd(User user,Stock stock){
		boolean isCanBuild = false;
		UserStockRlDto obj = new UserStockRlDto();
		obj.setStockCode(stock.getCode());
		obj.setYears("2016");
		obj.setUserName(user.getName());
		obj.setStatus("首补");
		
		List<UserStockRl> userStockRls = userStockRlMapper.findByCase(obj);
		if(userStockRls!=null&&userStockRls.size()>0){		
			isCanBuild = true;		
		}
		return isCanBuild;	
	}
	
	/**
	 * 计算首次补仓数量
	 * @param addCost 首次补仓加权成本
	 * @param stock
	 * @param user
	 * @return
	 * @throws Exception
	 */
	private Integer getFirstAddNumAfterBuild(Double addCost,Stock stock,User user,Double totalCost)throws Exception{
		Integer num = 0;
		//获取持有量
		UserStockRlDto obj = new UserStockRlDto();
		obj.setStockCode(stock.getCode());
		obj.setYears("2016");
		obj.setUserName(user.getName());
		obj.setStatus("建仓");
		List<UserStockRl> userStockRls = userStockRlMapper.findByCase(obj);	
		Integer currentNum = 0;
		if(userStockRls!=null&&userStockRls.size()>0){
			currentNum = userStockRls.get(0).getNum();//当前持有数
		}
		
		BigDecimal num_DoubleValue = new BigDecimal((totalCost-(currentNum*addCost))/(addCost));
		num_DoubleValue = num_DoubleValue.setScale(-2, BigDecimal.ROUND_HALF_UP);
		num = num_DoubleValue.intValue();
		return num;
	}
	
	/**
	 * 计算已经建仓的情况下 补仓的价格 适用于首次补仓和二次补仓 
	 * @param addCost 补仓加权成本
	 * @param stock
	 * @param user
	 * @param addNum 补仓数量
	 * @return
	 * @throws Exception
	 */
	private Double getFirstAddValueAfterBuild(Double addCost,Stock stock,User user,Integer addNum)throws Exception{
		Double firstAddValue = null;
		Integer currentNum = 0;//当前持有量
		Double currentCost = new Double(0);//当前成本
		//获取持有量
		UserStockRlDto obj = new UserStockRlDto();
		obj.setStockCode(stock.getCode());
		obj.setYears("2016");
		obj.setUserName(user.getName());
		List<UserStockRl> userStockRls = userStockRlMapper.findByCase(obj);	
		if(userStockRls!=null&&userStockRls.size()>0){
			currentNum = userStockRls.get(0).getNum();//当前持有量
			currentCost = userStockRls.get(0).getCost();//当前成本
		}
		firstAddValue = (addCost*(currentNum+addNum)-currentNum*currentCost)/addNum;
		//保留小数点后两位
		BigDecimal b = new BigDecimal(firstAddValue); 
		firstAddValue = b.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();   
		return firstAddValue;
	}
}
